import os
import re
import urlparse
import urllib
import uuid
import md5
import datetime
import Cookie

from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.api import urlfetch

import urlhelper
import cookiehelper
import logger

SESSION_ID = 'session_id'
SECURITY_KEY = 'security_key'

class IndexPage(webapp.RequestHandler):
	def __init__(self):
		self.__session_id = None

	def get(self):
		self.fetch(urlfetch.GET)

	def post(self):
		self.fetch(urlfetch.POST)

	def fetch(self, method):
		fetch_url = urlhelper.extract_fetch_url(self.request.url)
		if fetch_url:
			return self.show_fetch_content(fetch_url, method)
		refer_url = 'Referer' in self.request.headers and self.request.headers['Referer'] or ''
		fetch_url = urlhelper.build_fetch_url(refer_url, self.request.url)
		if fetch_url:
			return self.redirect_to(urlhelper.build_proxy_url(fetch_url))
		# TODO: show error messsage and redirect to index page
		return self.show_index_page()

	def show_index_page(self):
		path = os.path.join(os.path.dirname(__file__), 'index.html')
		self.response.out.write(template.render(path, {'action': urlhelper.PROXY_URL_PATH}))

	def redirect_to(self, redirect_url):
		self.response.set_status(301)
		self.response.headers['Location'] = redirect_url

	def show_fetch_content(self, fetch_url, method):
		trace_id = uuid.uuid4().hex
		logger.log(trace_id, logger.Role.user, logger.Role.proxy, fetch_url, self.request.headers, self.request.body)
		cookie = cookiehelper.SessionCookie(self.session_id)
		self.request.headers['Cookie'] = cookiehelper.join(self.request.headers.get('Cookie', ''), cookie.output_matched(fetch_url))
		if self.request.headers.get('Referer'):
			self.request.headers['Referer'] = urlhelper.extract_fetch_url(self.request.headers['Referer'])
		logger.log(trace_id, logger.Role.proxy, logger.Role.server, fetch_url, self.request.headers, self.request.body)
		result = urlfetch.fetch(fetch_url, self.request.body, method, headers=self.request.headers, follow_redirects=False)
		logger.log(trace_id, logger.Role.server, logger.Role.proxy, fetch_url, result.headers, result.content)
		cookie.update(fetch_url, result)
		self.response.set_status(result.status_code)
		for k,v in result.headers.iteritems():
			if 'location' in k.lower():
				v = urlhelper.build_proxy_url(v)
			self.response.headers[k] = v
		replace_content = urlhelper.replace_links(fetch_url, result.content)
		self.response.out.write(replace_content)
		logger.log(trace_id, logger.Role.proxy, logger.Role.user, fetch_url, self.response.headers, self.response.out.getvalue())

	def get_session_id(self):
		if self.__session_id:
			return self.__session_id
		if SESSION_ID not in self.request.cookies:
			self.__session_id = md5.new(uuid.uuid4().hex + SECURITY_KEY).hexdigest()
			cookies = Cookie.BaseCookie()
			cookies[SESSION_ID] = self.__session_id
			cookies[SESSION_ID]['path'] = '/'
			cookies[SESSION_ID]['expires'] = cookiehelper.strftime(datetime.datetime.utcnow() + datetime.timedelta(days=365))
			set_cookie_header = cookies.output(header='').lstrip()
			self.response.headers['Set-Cookie'] = set_cookie_header
		else:
			self.__session_id = self.request.cookies[SESSION_ID]
		return self.__session_id
	session_id = property(get_session_id)

application = webapp.WSGIApplication([
	 ('/log/list', logger.LogListPage), 
	 ('/log/show/(?P<id>\d+)', logger.LogShowPage), 
	 ('/log/clear', logger.LogClearPage), 
	 ('/.*', IndexPage)
	],
	debug=True
	)

def main():
	run_wsgi_app(application)

if __name__ == "__main__":
	main()
